/******************************************************************************
 * @file  gkt_cm0_irq.c
 * @date  4/Jan/2024
 ******************************************************************************/

#include "gkt_board.h"
#include "gkt_defines.h"
#include "gkt_types.h"
#include "gkt_debug.h"

/******************************************************************************
 * Fault handlers & System handlers
 ******************************************************************************/
void gkt_system_irq_default_handler(void)
{
#if defined(GKT_CONFIG_STDIO_ENABLE) && GKT_CONFIG_STDIO_ENABLE
	uint32_t irq_no;

	irq_no = (__get_IPSR() & IPSR_ISR_Msk);
	gkt_fatal("Core Exception - %u\n", irq_no);
#endif

	__BKPT(0);
}

/* dummy handlers if relevant handler does not exist */
void NMI_Handler(void) __WEAK __ALIAS(gkt_system_irq_default_handler);
void HardFault_Handler(void) __WEAK __ALIAS(gkt_system_irq_default_handler);
void SVC_Handler(void) __WEAK __ALIAS(gkt_system_irq_default_handler);
void PendSV_Handler(void) __WEAK __ALIAS(gkt_system_irq_default_handler);
void SysTick_Handler(void) __WEAK __ALIAS(gkt_system_irq_default_handler);

/******************************************************************************
 * Interrupts
 ******************************************************************************/
extern unsigned int *__MainStack_Top;
extern void Reset_Handler(void);

const gkt_irq_handler gc_sysirq_handlers[GKT_SYSIRQ_NUMS] 
		__USED __SECTION(.vectors.sysirq) = 
{
	(gkt_irq_handler)&__MainStack_Top,	/* Top of MainStack */
	Reset_Handler,		/* Reset Handler */
	NMI_Handler,		/* NMI Handler */
	HardFault_Handler,	/* HardFault Handler */
	0, 0, 0, 0, 0, 0, 0,			/* Reserved */
	SVC_Handler,		/* SVCall Handler */
	0, 0,				/* Reserved */
	PendSV_Handler,		/* PendSV Handler */
	SysTick_Handler,	/* SysTick Handler */
};


void __WEAK gkt_device_irq_default_handler(void)
{
	uint32_t irq_no;

	irq_no = (__get_IPSR() & IPSR_ISR_Msk) - GKT_SYSIRQ_NUMS;
	NVIC_DisableIRQ((IRQn_Type)irq_no);
	gkt_fatal("Unexpected Device Interrupt - %u\n", irq_no);
}

int gkt_irq_setup(uint32_t no, gkt_irq_attr_s *attr)
{
	if ((no < GKT_DEVIRQ_NUMS)
		&& attr && attr->handler
		&& (attr->priority >= GKT_IRQ_PRIORITY_SYSCALL)
		&& (attr->priority <= GKT_IRQ_PRIORITY_KERNEL))
	{
		/* 1st. disable interrupt */
		NVIC_DisableIRQ((IRQn_Type)no);

		/* 3rd. set priority */
		NVIC_SetPriority((IRQn_Type)no, attr->priority);

		/* 4th. clear pending? */
		if (attr->flags & GKT_IRQ_F_CLEAR)
			NVIC_ClearPendingIRQ((IRQn_Type)no);

		/* 5th. enable? */
		if (attr->flags & GKT_IRQ_F_ENABLE)
			NVIC_EnableIRQ((IRQn_Type)no);

		return GKT_SUCCESS;
	}

	return GKT_EPARAM;
}

void gkt_irq_release(uint32_t no)
{
	if (no < GKT_DEVIRQ_NUMS)
		NVIC_DisableIRQ((IRQn_Type)no);
}

int gkt_irq_context(void)
{
	return (__get_IPSR() != 0U);
}

uint32_t gkt_irq_get_current(void)
{
	return (__get_IPSR() & IPSR_ISR_Msk) - GKT_SYSIRQ_NUMS;
}

uint32_t gkt_irq_get_priority(uint32_t no)
{
	return (no < GKT_DEVIRQ_NUMS) ? 
				NVIC_GetPriority((IRQn_Type)no) :
				GKT_IRQ_PRIORITY_INVALID;
}
void gkt_irq_set_priority(uint32_t no, uint32_t priority)
{
	if ((no < GKT_DEVIRQ_NUMS) 
		&& (priority >= GKT_IRQ_PRIORITY_SYSCALL)
		&& (priority < GKT_IRQ_PRIORITY_KERNEL))
	{
		NVIC_SetPriority((IRQn_Type)no, priority);
	}
}

void gkt_irq_enable(uint32_t no)
{
	if (no < GKT_DEVIRQ_NUMS)
		NVIC_EnableIRQ((IRQn_Type)no);
}
void gkt_irq_disable(uint32_t no)
{
	if (no < GKT_DEVIRQ_NUMS)
		NVIC_DisableIRQ((IRQn_Type)no);
}

void gkt_irq_set_pending(uint32_t no)
{
	if (no < GKT_DEVIRQ_NUMS)
		NVIC_SetPendingIRQ((IRQn_Type)no);
}

void gkt_irq_clear_pending(uint32_t no)
{
	if (no < GKT_DEVIRQ_NUMS)
		NVIC_ClearPendingIRQ((IRQn_Type)no);
}

static __SYSINFO_BSS volatile int s_irq_global_nested_count;
__SRAM_TEXT void gkt_irq_global_disable(void)
{
	/* Disable interrupts and configurable fault handlers (set PRIMASK) */
	__disable_irq();
	__DSB();
	__ISB();

	s_irq_global_nested_count++;
}
__SRAM_TEXT void gkt_irq_global_enable(void)
{
	__ISB();
	__DSB();

	if (s_irq_global_nested_count) {
		s_irq_global_nested_count--;
		if (!s_irq_global_nested_count)
			__enable_irq();
	}
	else
		GKT_ASSERT(0);
}

void gkt_irq_init(void)
{
	/* dummy */
}


